package coins;

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Currency;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;

import strategies.Strategy;

import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IContext;
import com.dukascopy.api.INewsFilter;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.LoadingProgressListener;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.Period;
import com.dukascopy.api.INewsFilter.NewsSource;
import com.dukascopy.api.system.Commissions;
import com.dukascopy.api.system.IStrategyExceptionHandler;
import com.dukascopy.api.system.ISystemListener;
import com.dukascopy.api.system.ITesterClient;
import com.dukascopy.api.system.JFAuthenticationException;
import com.dukascopy.api.system.JFVersionException;
import com.dukascopy.api.system.Overnights;

public class TesterClient implements ITesterClient {

	private double initialDeposit;
	private int leverage;
	private double mcEquity;
	private int marginCutLevel;
	private Overnights overnights;
	private Set<Instrument> instruments = new HashSet<Instrument>();
	private Connection connection;
	private IStrategy strategy;
	private Instrument instrument = Instrument.EURUSD;
	private Period period;
	private Bar askbar;
	private Bar bidbar;
	private IContext context;
	private ITick tick;
	private Account account;

	public TesterClient(Period period) {
		instruments.add(Instrument.EURUSD);
		this.period = period;
		//Default settings
		account = new Account(Instrument.EURUSD.getSecondaryCurrency(), 1000, 100);
	}

	@Override
	public void createReport(File file) throws IOException,
			IllegalStateException {
		createReport(0, file);
	}

	@Override
	public void createReport(long processId, File file) throws IOException,
			IllegalStateException {
		/*
		 * double total = 0; PrintWriter writer = new PrintWriter(file); for
		 * (IOrder order : ((Engine) getContext().getEngine()).getAllOrders()) {
		 * writer.println(order); total += order.getProfitLossInUSD(); }
		 * writer.println(((Engine) getContext().getEngine()).getAllOrders()
		 * .size()); writer.println(total);
		 * writer.println(account.getDrawdown()); writer.close();
		 * Desktop.getDesktop().open(file);
		 */	}

	@Override
	public Future<?> downloadData(
			LoadingProgressListener loadingProgressListener) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public Commissions getCommissions() {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public boolean getEventLogEnabled() {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public boolean getGatherReportData() {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public double getInitialDeposit() {
		return initialDeposit;
	}

	@Override
	public Currency getInitialDepositCurrency() {
		return Instrument.EURUSD.getSecondaryCurrency();
	}
	
	public double getCurrentDeposit() {
		return account.getEquity();
	}

	@Override
	public int getLeverage() {
		return (int)account.getLeverage();
	}

	@Override
	public double getMCEquity() {
		return mcEquity;
	}

	@Override
	public int getMarginCutLevel() {
		return marginCutLevel;
	}

	@Override
	public Overnights getOvernights() {
		return overnights;
	}

	@Override
	public boolean getProcessingStats() {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setCommissions(Commissions commissions) {
	}

	@Override
	public void setDataInterval(Period period, OfferSide side,
			InterpolationMethod interpolationMethod, long from, long to) {
	}

	@Override
	public void setEventLogEnabled(boolean eventLogEnabled) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setGatherReportData(boolean gatherReportData) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setInitialDeposit(Currency currency, double deposit)
			throws IllegalArgumentException {
		this.initialDeposit = deposit;
	}

	@Override
	public void setLeverage(int leverage) {
		this.leverage = leverage;
	}

	@Override
	public void setMCEquity(double mcEquity) {
		this.mcEquity = mcEquity;
	}

	@Override
	public void setMarginCutLevel(int mcLevel) {
		marginCutLevel = mcLevel;
	}

	@Override
	public void setOvernights(Overnights overnights) {
		this.overnights = overnights;
	}

	@Override
	public void setProcessingStatsEnabled(boolean processingStats) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public long startStrategy(IStrategy strategy,
			LoadingProgressListener testerProgressListener)
			throws IllegalStateException, NullPointerException {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public long startStrategy(IStrategy strategy,
			IStrategyExceptionHandler exceptionHandler,
			LoadingProgressListener testerProgressListener)
			throws IllegalStateException, NullPointerException {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void addNewsFilter(INewsFilter newsFilter) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void connect(String url, String username, String password)
			throws JFAuthenticationException, JFVersionException, Exception {

	}

	@Override
	public INewsFilter getNewsFilter(NewsSource newsSource) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public Map<Long, IStrategy> getStartedStrategies() {
		return null;
	}

	@Override
	public Set<Instrument> getSubscribedInstruments() {
		return instruments;
	}

	@Override
	public boolean isConnected() {
		try {
			return connection.isClosed() == false;
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public IStrategy loadStrategy(File strategyBinaryFile) throws Exception {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void reconnect() {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public INewsFilter removeNewsFilter(NewsSource newsSource) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setCacheDirectory(File cacheDirectory) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setErr(PrintStream err) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setOut(PrintStream out) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setSubscribedInstruments(Set<Instrument> instruments) {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void setSystemListener(ISystemListener systemListener) {
	}

	@Override
	public long startStrategy(IStrategy strategy) throws IllegalStateException,
			NullPointerException {
		// mark as current strategy
		this.strategy = strategy;

		// Load data from database
		try {
			// Create a streaming result set
			context = new Context(new Engine(this));
			strategy.onStart(context);
			strategy.onAccount(account);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return 0;
	}

	public IContext getContext() {
		return context;
	}

	public void setContext(IContext context) {
		this.context = context;
	}

	public void onTick(Tick tick) throws Exception {
		this.tick = tick;

		// Intimate strategy about tick
		((Engine)getContext().getEngine()).update(tick);
		strategy.onTick(instrument, tick);
	}

	public void onTickOld(Tick tick) throws Exception {
		this.tick = tick;

		// Intimate strategy about tick
		strategy.onTick(instrument, tick);

		// Update the bar
		try {
			if ((tick.getTime() - askbar.getTime()) >= period.getInterval()) {
				strategy.onBar(instrument, period, askbar, bidbar);
				//calculateDrawdown();
				askbar = new Bar(tick.getTime(), tick.getAsk(), tick
						.getAskVolume());
				bidbar = new Bar(tick.getTime(), tick.getBid(), tick
						.getAskVolume());
			}
			askbar.update(tick.getAsk(), tick.getAskVolume(), tick.getTime());
			bidbar.update(tick.getBid(), tick.getBidVolume(), tick.getTime());
		} catch (NullPointerException ex) {
			askbar = new Bar(tick.getTime(), tick.getAsk(), tick.getAskVolume());
			bidbar = new Bar(tick.getTime(), tick.getBid(), tick.getBidVolume());

		}
	}

	public void onBar(Instrument instrument, Period period, IBar askBar,
			IBar bidBar) throws Exception {
		// Intimate strategy about tick
		strategy.onBar(instrument, period, askBar, bidBar);
		//calculateDrawdown();
	}

	public ITick getTick() {
		return tick;
	}

	public void setTick(ITick tick) {
		this.tick = tick;
	}

	@Override
	public long startStrategy(IStrategy strategy,
			IStrategyExceptionHandler exceptionHandler)
			throws IllegalStateException, NullPointerException {
		throw new RuntimeException("Not implemented");
	}

	@Override
	public void stopStrategy(long processId) {
		try {
			strategy.onStop();
			List<IOrder> orders = getContext().getEngine()
					.getOrders(instrument);
			if (orders.size() > 0)
				((Order) orders.get(0)).setCloseTick(tick);
			createReport(new File(strategy.toString()
					+ ".txt"));
			String file = ((Strategy)strategy).writeOrders("");
			Desktop.getDesktop().open(new File(file));
		} catch (JFException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public double updateCurrentDeposit(double amount)
	{
		try{
		account.updateCurrentDeposit(amount);
		}
		catch (RuntimeException e)
		{
			System.out.println("Account out of money. Balance = "+account.getEquity());
			stopStrategy(0);
			try
			{
				createReport(new File(strategy.toString() + ".txt"));
			}catch (Exception ex) {
				ex.printStackTrace();
			}
			System.exit(0);
		}
		return account.getEquity();
	}

	public Account getAccount() {
		return account;
	}
}
